home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Night Owl 6
/
Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso
/
008a
/
emslb221.zip
/
EMSTEST.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-10-13
|
89KB
|
2,056 lines
/***************************************************************************
* emstest.c *
* MODULE: EMSLIB *
* OS: DOS *
* VERSION: 1.0 *
* DATE: 09/25/91 *
* *
* Copyright (c) 1991 James W. Birdsall. All Rights Reserved. *
* *
* Requires emslib.h and emstest.h to compile. *
* Compiles under Borland C++ 2.0 or MSC 6.00A. *
* *
* Regression test and example for EMSLIB. *
* *
* This is part one of the regression tester and example for EMSLIB. *
* The other parts are named EMSTEST2.C and EMSTEST3.C. All three parts *
* must be compiled and linked together along with the appropriate EMSLIB *
* library to produce the tester executable. This program compiles under *
* tiny, small, medium, compact, large, and huge models. Note that it *
* doesn't quite fit into tiny model; the tiny model tester is actually *
* three executables. When compiling for tiny model, one of the symbols *
* TINYPASS1, TINYPASS2, or TINYPASS3 must be defined. See the example *
* makefiles for further details on what needs to be linked with what *
* to produce the tiny-model executables. *
* *
* To use this tester: just run it. It requires no arguments and produces *
* output on stdout. It performs nearly 200 tests and parts of it run *
* quite fast, even on an original IBM PC/XT (4.77 MHz). If you want to *
* actually read the output, you should redirect the output to a file. *
* If you just want to see whether the tests all pass, just run it -- *
* if a test fails, execution aborts immediately. *
* *
* Certain types of failure may cause EMSTEST to not deallocate EMS or *
* conventional memory that it has allocated. This should only occur if *
* the library itself is malfunctioning (which should never happen to *
* you, only to me!) or if you are trying a different compiler or *
* unsupported memory model and the compiler and library are therefore *
* not communicating properly. It may also happen if you press control- *
* break. *
* *
* To improve speed, some basic functions are coded in in-line assembly *
* language. The in-line assembly is compatible with Turbo/Borland C[++] *
* and MSC 6.00A. Since earlier versions of Turbo C required an external *
* assembler to support in-line assembly, and I don't know whether *
* earlier versions of MSC supported it at all, the functions also have *
* alternate C versions. The C versions are compiled by default; to get *
* the in-line assembly versions, you must define the symbol INLINE_ASM. *
* *
* Turbo C and older versions of Turbo C++ do not have the _fmemcmp() and *
* _fmemset() functions; I don't know about older versions of MSC. If *
* your compiler does not have these functions, define the symbol *
* NO_FFUNC and functions in this file will be used instead. *
* *
***************************************************************************/
/*
** system includes <>
*/
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
/*
** custom includes ""
*/
#include "emslib.h"
#include "emstest.h"
/*
** local #defines
*/
/*
** misc: copyright strings, version macros, etc.
*/
/*
** typedefs
*/
/*
** global variables
*/
int testno = 1; /* number of test currently being done */
unsigned char far *frameptr[4]; /* pointers to EMS frames */
char *gblmsg = ""; /* msg to be printed in test header */
/*
** static globals
*/
/*
** function prototypes
*/
static unsigned char huge *normptr(unsigned char far *norm);
/*
** functions
*/
/***************************************************************************
* FUNCTION: MAIN *
* *
* DESCRIPTION: *
* *
* The master function. *
* *
* ENTRY: *
* *
* None. *
* *
* EXIT: *
* *
* Void. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
main()
{
int status; /* return status from library functions */
/*
** check initialization test
*/
TESTHEADER();
printf("Making a call to EMMgetversion() before calling EMMlibinit().\n");
printf("The call should fail.\n");
EMMgetversion();
nofailcheck("EMMgetversion()", (int) _EMMerror, NULL, 0, 0);
weirdcodechk("EMMgetversion()", EMM_NOINIT, NULL, 0, 0);
TESTTAILER();
/*
** initialize EMSLIB
*/
TESTHEADER();
printf("Calling EMMlibinit().\n");
printf("Should succeed if Expanded Memory Manager is present.\n");
status = EMMlibinit();
switch (status)
{
case EMMOOPS:
printf("EMMlibinit() failed, code 0x%X.\n",
(unsigned int) _EMMerror);
exit(3);
break;
case NOEMM:
printf("EMMlibinit() did not find an Expanded Memory Manager.\n");
exit(3);
break;
case 0:
printf("EMMlibinit() returned OK.\n");
weirdcodechk("EMMlibinit()", 0, NULL, 0, 0);
break;
default:
printf("EMMlibinit() returned strange value %d.\n", status);
exit(3);
break;
}
TESTTAILER();
/*
** The following section of code is included only in the first tiny-model
** executable and in non-tiny-model executables.
*/
#ifndef TINYPASS2
#ifndef TINYPASS3
/*
** test version call
*/
TESTHEADER();
printf("Testing EMMgetversion().\n");
printf("Results should match value in _EMMversion.\n");
status = EMMgetversion();
weirdcodechk("EMMgetversion()", 0, NULL, 0, 0);
if (status != (int) _EMMversion)
{
printf("EMMgetversion() [0x%X] and _EMMversion [0x%X] differ.\n",
status, (unsigned int) _EMMversion);
exit(3);
}
printf("EMS version %d.%d.\n", ((status >> 4) & 0xF), (status & 0xF));
TESTTAILER();
/*
** test allocation functions
*/
do_alloc_tests(1L);
do_alloc_tests(16384L);
do_alloc_tests(55555L);
do_alloc_tests(0L);
do_palloc_tests(1);
do_palloc_tests(5);
#endif
#endif
/*
** test frame functions -- included in all executables
*/
do_frame_tests();
/*
** The following section of code is included only in the first tiny-model
** executable and in non-tiny-model executables.
*/
#ifndef TINYPASS2
#ifndef TINYPASS3
/*
** test name functions
*/
do_name_tests();
/*
** do mapping tests
*/
do_map_tests();
/*
** test the save/restore facility
*/
do_sr_tests();
#endif
#endif
/*
** The following section of code is included only in the second tiny-model
** executable and in non-tiny-model executables.
*/
#ifndef TINYPASS1
#ifndef TINYPASS3
/*
** test copies of <= one page, frame caching on
*/
gblmsg = " SHORT COPY TESTS";
do_shortcopy_tests();
gblmsg = "";
/*
** test frame cache control
*/
TESTHEADER();
printf("Testing frame caching enable/disable.\n");
if (_EMMframecache == 0)
{
printf("Frame caching is supposed to be on by default, seems to ");
printf("be off.\n");
exit(3);
}
_EMMdisc();
weirdcodechk("_EMMdisc()", 0, NULL, 0, 0);
if (_EMMframecache != 0)
{
printf("_EMMdisc() did not disable frame caching.\n");
exit(3);
}
_EMMenc();
weirdcodechk("_EMMenc()", 0, NULL, 0, 0);
if (_EMMframecache == 0)
{
printf("_EMMenc() did not enable frame caching.\n");
exit(3);
}
printf("Flag and function calls correspond OK.\n");
TESTTAILER();
/*
** test copies of <= one page, frame caching off
*/
_EMMdisc();
gblmsg = " SHORT COPY TESTS WITH FRAME CACHING OFF";
do_shortcopy_tests();
_EMMenc();
#endif
/*
** The following section of code is included only in the third tiny-model
** executable and in non-tiny-model executables.
*/
#ifndef TINYPASS2
/*
** test copies of > 1 page, frame caching on
*/
_EMMenc();
gblmsg = " LONG COPY TESTS";
do_longcopy_tests();
/*
** test copies of > 1 page, frame caching off
*/
_EMMdisc();
gblmsg = " LONG COPY TESTS WITH FRAME CACHING OFF";
do_longcopy_tests();
gblmsg = "";
_EMMenc();
#endif
#endif
/* end and cleanup */
printf(">>>END\n");
printf("All tests succeeded.\n");
exit(0);
} /* end of main() */
/***************************************************************************
* FUNCTION: DO_FRAME_TESTS *
* *
* DESCRIPTION: *
* *
* This function tests EMSLIB calls EMMgetnumframe(), *
* EMMgetframeaddr(), and EMMgetsinfraddr(). *
* *
* ENTRY: *
* *
* Void. *
* *
* EXIT: *
* *
* Void. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
* Fills in the frameptr[] global array. *
* *
***************************************************************************/
void do_frame_tests(void)
{
frameinfo *framebuf;
int frames;
int status;
int loop;
unsigned int segaddr;
/* get number of frames */
TESTHEADER();
printf("Getting number of frames with EMMgetnumframe().\n");
if (_EMMversion < 0x40)
{
printf("Should be exactly 4.\n");
}
else
{
printf("Should be 4 or more.\n");
}
frames = EMMgetnumframe();
weirdcodechk("EMMgetnumframe()", 0, NULL, 0, 0);
if (frames < 4)
{
printf("EMMgetnumframe() returned OK but indicates only %d frames.\n",
frames);
exit(3);
}
if ((_EMMversion < 0x40) && (frames != 4))
{
printf("EMMgetnumframe() returned OK but indicates wrong number of\n");
printf(" frames (%d) for this version.\n", frames);
exit(3);
}
printf("EMMgetnumframe() returned OK, %d frames.\n", frames);
TESTTAILER();
/* allocate memory for frame address buffer */
framebuf = (frameinfo *) calloc(frames, sizeof(frameinfo));
if (framebuf == (frameinfo *) NULL)
{
printf("OOPS! Couldn't allocate a buffer. Aborting.\n");
exit(3);
}
/* get frame segment addresses */
TESTHEADER();
printf("Getting frame address info with EMMgetframeaddr().\n");
printf("Should succeed.\n");
status = EMMgetframeaddr(framebuf);
TRIPLECHECK("EMMgetframeaddr()", status, 0, framebuf, 0, 0);
printf("EMMgetframeaddr() returned OK, checking info returned...\n");
for (loop = 0; loop < frames; loop++)
{
/* check for valid frame number */
if (framebuf[loop].frameno >= frames)
{
printf("Frame number in slot %d is bad (%u).\n", loop,
framebuf[loop].frameno);
free(framebuf);
exit(3);
}
/* check that frame segment address is on a page (16K) boundary */
if ((framebuf[loop].segaddr & 0x3FF) != 0)
{
printf(
"Frame segment %u, slot %d, frame number %u, not page aligned.\n",
framebuf[loop].segaddr, loop, framebuf[loop].frameno);
free(framebuf);
exit(3);
}
/* if one of frames 0-3, save the address */
if (framebuf[loop].frameno < 4)
{
frameptr[framebuf[loop].frameno] = (unsigned char far *)
MK_FP(framebuf[loop].segaddr, 0);
}
}
printf("Info returned checks out OK.\n");
TESTTAILER();
/* now test EMMgetsinfraddr() */
TESTHEADER();
printf("Testing EMMgetsinfraddr() against data from EMMgetframeaddr().\n");
printf("Should succeed.\n");
/* loop through framebuf, calling EMMgetsinfraddr() on each */
for (loop = 0; loop < frames; loop++)
{
segaddr = EMMgetsinfraddr(framebuf[loop].frameno);
weirdcodechk("EMMgetsinfraddr()", 0, framebuf, 0, 0);
if (segaddr != framebuf[loop].segaddr)
{
printf("EMMgetsinfraddr(%u) succeeded but returned %u, not %u.\n",
framebuf[loop].frameno, segaddr, framebuf[loop].segaddr);
free(framebuf);
exit(3);
}
}
printf("EMMgetsinfraddr() returned all addresses OK.\n");
TESTTAILER();
/* clean up */
free(framebuf);
return;
} /* end of do_frame_tests() */
/*
** The following section of code is included only in the first tiny-model
** executable and in non-tiny-model executables.
*/
#ifndef TINYPASS2
#ifndef TINYPASS3
/***************************************************************************
* FUNCTION: DO_ALLOC_TESTS *
* *
* DESCRIPTION: *
* *
* This function tests EMSLIB calls EMMcoreleft(), EMMalloc(), and *
* EMMfree(). *
* *
* ENTRY: *
* *
* bytes - number of bytes of EMS to try to allocate. *
* *
* EXIT: *
* *
* Void. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void do_alloc_tests(unsigned long bytes)
{
unsigned long emsfree, emsfree2;
unsigned long pagelen;
int handle;
/* get bytes value rounded up to nearest page, or 1 page if bytes == 0 */
if (bytes != 0L)
{
pagelen = bytes + 16383L;
pagelen &= 0xFFFFC000L;
}
else
{
pagelen = 16384L;
}
/* test coreleft */
TESTHEADER();
printf("Testing EMMcoreleft().\n");
printf("Result should be multiple of 16384.\n");
emsfree = test_EMMcoreleft();
printf("EMMcoreleft() returned OK, shows %lu bytes (%lu pages) free.\n",
emsfree, (emsfree / 16384L));
TESTTAILER();
/* make sure enough free */
if (emsfree < (MINFREE * 16384L))
{
printf("Insufficient free EMS to perform all tests. Aborting.\n");
exit(1);
}
/* test allocation */
TESTHEADER();
printf("Testing EMMalloc(%lu).\n", bytes);
printf("Should succeed. Free EMS should drop by %lu bytes (%lu pages).\n",
pagelen, (pagelen / 16384L));
handle = test_EMMalloc(bytes);
printf("EMMalloc() returned OK.\n");
emsfree2 = test_EMMcoreleft();
printf("EMMcoreleft() returned OK, shows %lu bytes (%lu pages) free.\n",
emsfree2, (emsfree2 / 16384L));
if ((emsfree - emsfree2) != pagelen)
{
printf("EMMalloc(%lu) caused free to drop weirdly from %lu to %lu.\n",
bytes, emsfree, emsfree2);
EMMfree(handle);
exit(3);
}
TESTTAILER();
/* test free */
TESTHEADER();
printf("Testing EMMfree() on handle just returned by EMMalloc().\n");
printf(
"Should succeed. Free EMS should increase by %lu bytes (%lu pages).\n",
pagelen, (pagelen / 16384L));
test_EMMfree(handle);
printf("EMMfree() returned OK.\n");
emsfree2 = test_EMMcoreleft();
printf("EMMcoreleft() returned OK, shows %lu bytes (%lu pages) free.\n",
emsfree2, (emsfree2 / 16384L));
if (emsfree2 != emsfree)
{
printf("Freeing handle returned by EMMalloc() did not restore\n");
printf(" free EMS count -- was %lu originally, now %lu.\n", emsfree,
emsfree2);
exit(3);
}
TESTTAILER();
return;
} /* end of do_alloc_tests() */
/***************************************************************************
* FUNCTION: DO_PALLOC_TESTS *
* *
* DESCRIPTION: *
* *
* This function tests EMSLIB calls EMMcoreleft(), EMMallocpages(), *
* and EMMfree(). *
* *
* ENTRY: *
* *
* pages - number of pages of EMS to try to allocate. *
* *
* EXIT: *
* *
* Void. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void do_palloc_tests(int pages)
{
unsigned long emsfree, emsfree2;
unsigned long pagelen;
int handle;
/* convert pages to bytes */
pagelen = 16384L * pages;
/* test coreleft */
TESTHEADER();
printf("Testing EMMcoreleft().\n");
printf("Result should be multiple of 16384.\n");
emsfree = test_EMMcoreleft();
printf("EMMcoreleft() returned OK, shows %lu bytes (%lu pages) free.\n",
emsfree, (emsfree / 16384L));
TESTTAILER();
/* make sure enough free */
if (emsfree < (MINFREE * 16384L))
{
printf("Insufficient free EMS to perform all tests. Aborting.\n");
exit(1);
}
/* test allocation */
TESTHEADER();
printf("Testing EMMallocpages(%d).\n", pages);
printf("Should succeed. Free EMS should drop by %lu bytes (%lu pages).\n",
pagelen, (pagelen / 16384L));
handle = test_EMMallocpages(pages);
printf("EMMallocpages() retured OK.\n");
emsfree2 = test_EMMcoreleft();
printf("EMMcoreleft() returned OK, shows %lu bytes (%lu pages) free.\n",
emsfree2, (emsfree2 / 16384L));
if ((emsfree - emsfree2) != pagelen)
{
printf(
"EMMallocpages(%d) caused free to drop weirdly from %lu to %lu.\n",
pages, emsfree, emsfree2);
EMMfree(handle);
exit(3);
}
TESTTAILER();
/* test free */
TESTHEADER();
printf("Testing EMMfree() on handle just returned by EMMallocpages().\n");
printf(
"Should succeed. Free EMS should increase by %lu bytes (%lu pages).\n",
pagelen, (pagelen / 16384L));
test_EMMfree(handle);
printf("EMMfree() returned OK.\n");
emsfree2 = test_EMMcoreleft();
printf("EMMcoreleft() returned OK, shows %lu bytes (%lu pages) free.\n",
emsfree2, (emsfree2 / 16384L));
if (emsfree2 != emsfree)
{
printf("Freeing handle returned by EMMallocpages() did not restore\n");
printf(" free EMS count -- was %lu originally, now %lu.\n", emsfree,
emsfree2);
exit(3);
}
TESTTAILER();
return;
} /* end of do_palloc_tests() */
/***************************************************************************
* FUNCTION: DO_NAME_TESTS *
* *
* DESCRIPTION: *
* *
* This function tests EMSLIB calls EMMgetname() and EMMsetname(). *
* *
* ENTRY: *
* *
* Void. *
* *
* EXIT: *
* *
* Void. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void do_name_tests(void)
{
char name[9];
int handle, status;
TESTHEADER();
printf("Testing EMMsetname() and EMMgetname().\n");
if (_EMMversion < 0x40)
{
printf(
"EMMsetname() should fail, EMMgetname() return empty buffer.\n");
}
else
{
printf("Should succeed.\n");
}
/* allocate some EMS to assign a name to */
handle = test_EMMalloc(16384);
printf("Calling EMMsetname() with name ABCDEFGH.\n");
status = EMMsetname(handle, "ABCDEFGH");
if (_EMMversion < 0x40)
{
nofailcheck("EMMsetname()", status, NULL, handle, 0);
weirdretchk("EMMsetname()", status, NULL, handle, 0);
weirdcodechk("EMMsetname()", EMM_BADVERS, NULL, handle, 0);
printf("EMMsetname() failed OK.\n");
}
else
{
TRIPLECHECK("EMMsetname()", status, 0, NULL, handle, 0);
printf("EMMsetname() succeeded.\n");
}
printf("Now calling EMMgetname().\n");
status = EMMgetname(handle, name);
TRIPLECHECK("EMMgetname()", status, 0, NULL, handle, 0);
if (_EMMversion < 0x40)
{
if (farmemcheck((unsigned char far *) name, 9, '\0') != 0)
{
printf("A character in name is not null.\n");
EMMfree(handle);
exit(3);
}
}
else
{
if (strcmp(name, "ABCDEFGH") != 0)
{
printf("Got name %s back.\n", name);
EMMfree(handle);
exit(3);
}
}
printf("EMMgetname() succeeded.\n");
test_EMMfree(handle);
TESTTAILER();
return;
} /* end of do_name_tests() */
/***************************************************************************
* FUNCTION: DO_MAP_TESTS *
* *
* DESCRIPTION: *
* *
* This function tests EMSLIB call EMMmappage(). *
* *
* ENTRY: *
* *
* Void. *
* *
* EXIT: *
* *
* Void. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void do_map_tests(void)
{
int handle1, handle2;
int loop;
int status;
/* first, allocate some EMS to map */
handle1 = test_EMMallocpages(6);
handle2 = test_EMMallocpages(2);
/* initial test of EMMmappage() */
TESTHEADER();
printf("Calling EMMmappage(frameno = 0, first handle, logpage = 0).\n");
printf("Should succeed.\n");
test_EMMmappage(0, handle1, 0);
printf("EMMmappage() returned OK.\n");
TESTTAILER();
/* calling EMMmappage() with a bad logical page number */
TESTHEADER();
printf("Calling EMMmappage(frameno = 0, first handle, logpage = 6).\n");
printf("Should fail.\n");
status = EMMmappage(0, handle1, 6);
nofailcheck("EMMmappage()", status, NULL, handle1, handle2);
weirdretchk("EMMmappage()", status, NULL, handle1, handle2);
weirdcodechk("EMMmappage()", EMM_BADLOGPAGE, NULL, handle1, handle2);
printf("EMMmappage() failed OK.\n");
TESTTAILER();
TESTHEADER();
printf("Writing data pattern to page 0, first handle... ");
FMEMSET(frameptr[0], 0, 16384);
printf("Verifying... ");
if (farmemcheck(frameptr[0], 16384, 0) != 0)
{
printf("Verify failed!\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
printf("OK.\n");
printf("Calling EMMmappage(frameno = 0, first handle, logpage = 1).\n");
test_EMMmappage(0, handle1, 1);
printf("EMMmappage() returned OK.\n");
printf("Writing data pattern to page 1, first handle... ");
FMEMSET(frameptr[0], 1, 16384);
printf("Verifying... ");
if (farmemcheck(frameptr[0], 16384, 1) != 0)
{
printf("Verify failed!\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
printf("OK.\n");
printf("Now mapping page 0 back, see if it's still OK.\n");
test_EMMmappage(0, handle1, 0);
printf("EMMmappage() returned OK, verifying contents... ");
if (farmemcheck(frameptr[0], 16384, 0) != 0)
{
printf("Verify failed!\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
printf("OK.\n");
printf("EMMmappage() looks like it's doing something.\n");
TESTTAILER();
TESTHEADER();
printf("Testing mapping of all frames...\n");
printf("Filling rest of allocated pages with unique patterns... ");
for (loop = 2; loop < 6; loop++)
{
test_EMMmappage(0, handle1, loop);
FMEMSET(frameptr[0], loop, 16384);
if (farmemcheck(frameptr[0], 16384, (unsigned char) loop) != 0)
{
printf("Verify failed on handle 1, page %d.\n", loop);
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
}
test_EMMmappage(0, handle2, 0);
FMEMSET(frameptr[0], 0x10, 16384);
if (farmemcheck(frameptr[0], 16384, 0x10) != 0)
{
printf("Verify failed on handle 2, page 0!\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
test_EMMmappage(0, handle2, 1);
FMEMSET(frameptr[0], 0x11, 16384);
if (farmemcheck(frameptr[0], 16384, 0x11) != 0)
{
printf("Verify failed on handle 2, page 1!\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
printf("Done.\n");
printf("Mapping handle 1 pages 0-3 in frames 0-3 respectively... ");
for (loop = 0; loop < 4; loop++)
{
test_EMMmappage(loop, handle1, loop);
}
printf("Done.\n");
printf("Verifying contents... ");
for (loop = 0; loop < 4; loop++)
{
if (farmemcheck(frameptr[loop], 16384, (unsigned char) loop) != 0)
{
printf("Verify failed for frame %d.\n", loop);
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
}
printf("OK.\n");
printf("Mapping handle 1 pages 0-3 in frames 0-3 in reverse... ");
for (loop = 0; loop < 4; loop++)
{
test_EMMmappage(loop, handle1, (3 - loop));
}
printf("Done.\n");
printf("Verifying contents... ");
for (loop = 0; loop < 4; loop++)
{
if (farmemcheck(frameptr[loop], 16384, (unsigned char)(3 - loop)) != 0)
{
printf("Verify failed for frame %d.\n", loop);
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
}
printf("OK.\n");
printf(
"Mapping handle 1 pages 0-3 in frames 0-3 except page 5 in frame 2... ");
for (loop = 0; loop < 4; loop++)
{
test_EMMmappage(loop, handle1, loop);
}
test_EMMmappage(2, handle1, 5);
printf("Done.\n");
printf("Verifying contents... ");
for (loop = 0; loop < 4; loop++)
{
if (farmemcheck(frameptr[loop], 16384,
(unsigned char)((loop != 2) ? loop : 5)) != 0)
{
printf("Verify failed for frame %d.\n", loop);
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
}
printf("OK.\n");
TESTTAILER();
TESTHEADER();
printf("Final mapping test... two handles at once!\n");
printf("Mapping handle2 page 1 in frame 0.\n");
printf(" handle1 page 4 in frame 1.\n");
printf(" handle1 page 0 in frame 2.\n");
printf(" handle2 page 0 in frame 3.\n");
test_EMMmappage(0, handle2, 1);
test_EMMmappage(1, handle1, 4);
test_EMMmappage(2, handle1, 0);
test_EMMmappage(3, handle2, 0);
printf("Mapping done. Verifying... ");
if (farmemcheck(frameptr[0], 16384, 0x11) != 0)
{
printf("Verify failed for frame 0.\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
if (farmemcheck(frameptr[1], 16384, 4) != 0)
{
printf("Verify failed for frame 1.\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
if (farmemcheck(frameptr[2], 16384, 0) != 0)
{
printf("Verify failed for frame 2.\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
if (farmemcheck(frameptr[3], 16384, 0x10) != 0)
{
printf("Verify failed for frame 3.\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
printf("OK.\n");
TESTTAILER();
/* clean up */
test_EMMfree(handle1);
test_EMMfree(handle2);
return;
} /* end of do_map_tests() */
/***************************************************************************
* FUNCTION: DO_SR_TESTS *
* *
* DESCRIPTION: *
* *
* This function tests the EMSLIB mapping save/restore functions: *
* EMMsrinit(), EMMsave(), EMMrestore(). *
* *
* ENTRY: *
* *
* Void. *
* *
* EXIT: *
* *
* Void. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void do_sr_tests(void)
{
void *savehandle;
int handle1, handle2;
int status;
int loop;
/* first, allocate some EMS and fill with unique patterns */
handle1 = test_EMMallocpages(6);
handle2 = test_EMMallocpages(2);
for (loop = 0; loop < 6; loop++)
{
test_EMMmappage(0, handle1, loop);
FMEMSET(frameptr[0], loop, 16384);
if (farmemcheck(frameptr[0], 16384, (unsigned char) loop) != 0)
{
printf("Verify failed on handle 1, page %d.\n", loop);
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
}
test_EMMmappage(0, handle2, 0);
FMEMSET(frameptr[0], 0x10, 16384);
if (farmemcheck(frameptr[0], 16384, 0x10) != 0)
{
printf("Verify failed on handle 2, page 0!\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
test_EMMmappage(0, handle2, 1);
FMEMSET(frameptr[0], 0x11, 16384);
if (farmemcheck(frameptr[0], 16384, 0x11) != 0)
{
printf("Verify failed on handle 2, page 1!\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
TESTHEADER();
printf(
"Testing save/restore facility. Calling EMMsave() before EMMsrinit().\n");
printf("Should fail.\n");
savehandle = EMMsave();
nofailcheck("EMMsave()", (int) _EMMerror, NULL, handle1, handle2);
weirdcodechk("EMMsave()", EMM_NOSR, NULL, handle1, handle2);
printf("EMMsave() failed OK.\n");
TESTTAILER();
TESTHEADER();
printf("Calling EMMsrinit().\nShould succeed.\n");
status = EMMsrinit(malloc);
TRIPLECHECK("EMMsrinit()", status, 0, NULL, handle1, handle2);
printf("EMMsrinit() succeeded; save/restore facility initialized.\n");
TESTTAILER();
TESTHEADER();
printf("Testing EMMsave().\n");
printf("Mapping handle 1 pages 0-3 in frames 0-3 respectively.\n");
for (loop = 0; loop < 4; loop++)
{
test_EMMmappage(loop, handle1, loop);
}
printf("Calling EMMsave() to save current configuration.\n");
printf("Should succeed.\n");
savehandle = (void *) NULL;
savehandle = EMMsave();
if (savehandle == (void *) NULL)
{
printf("EMMsave() did not return anything, code 0x%X.\n",
(unsigned int) _EMMerror);
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
weirdcodechk("EMMsave()", 0, NULL, handle1, handle2);
printf("EMMsave() succeeded.\n");
TESTTAILER();
printf("Changing configuration.\n");
test_EMMmappage(0, handle2, 1);
test_EMMmappage(1, handle1, 4);
test_EMMmappage(2, handle1, 0);
test_EMMmappage(3, handle2, 0);
TESTHEADER();
printf("Calling EMMrestore() to restore previous configuration.\n");
printf("Should succeed.\n");
status = EMMrestore(savehandle);
TRIPLECHECK("EMMrestore()", status, 0, NULL, handle1, handle2);
printf("EMMrestore() returned OK, verifying contents... ");
for (loop = 0; loop < 4; loop++)
{
if (farmemcheck(frameptr[loop], 16384, (unsigned char) loop) != 0)
{
printf("Verify failed for frame %d.\n", loop);
test_EMMfree(handle1);
test_EMMfree(handle2);
exit(3);
}
}
printf("OK.\n");
TESTTAILER();
printf("Cleaning up.\n");
test_EMMfree(handle1);
test_EMMfree(handle2);
free(savehandle);
return;
} /* end of do_sr_tests() */
#endif
#endif
/*
** The following group of functions {test_EMM*()} are wrapper functions
** that call the EMSLIB function named and perform preliminary checks on
** the return values. This keeps code size down since the check only has
** to be coded in one place.
*/
/***************************************************************************
* FUNCTION: TEST_EMMCORELEFT *
* *
* DESCRIPTION: *
* *
* This function calls EMSLIB function EMMcoreleft() and checks the *
* return value to see if it is a multiple of 16384 (the EMS page *
* size). *
* *
* ENTRY: *
* *
* Void. *
* *
* EXIT: *
* *
* Returns the value returned by EMMcoreleft(). *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
unsigned long test_EMMcoreleft(void)
{
unsigned long emsfree;
/* call EMMcoreleft and check error code */
emsfree = EMMcoreleft();
weirdcodechk("EMMcoreleft()", 0, NULL, 0, 0);
/* check if free byte count is multiple of 16384 */
if ((emsfree % 16384L) != 0)
{
printf("EMMcoreleft() returned strange number %lu.\n", emsfree);
exit(3);
}
return emsfree;
} /* end of test_EMMcoreleft() */
/***************************************************************************
* FUNCTION: TEST_EMMALLOC *
* *
* DESCRIPTION: *
* *
* This function calls EMSLIB function EMMalloc() and checks the *
* return codes. *
* *
* ENTRY: *
* *
* bytes - bytes of EMS to allocate *
* *
* EXIT: *
* *
* Returns the handle returned by EMMalloc(). *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
int test_EMMalloc(unsigned long bytes)
{
int handle;
/* call EMMalloc() and check the return */
handle = EMMalloc(bytes);
weirdcodechk("EMMalloc()", 0, NULL, 0, 0);
return handle;
} /* end of test_EMMalloc() */
/***************************************************************************
* FUNCTION: TEST_EMMALLOCPAGES *
* *
* DESCRIPTION: *
* *
* This function calls EMSLIB function EMMallocpages() and checks the *
* return codes. *
* *
* ENTRY: *
* *
* pages - pages of EMS to allocate *
* *
* EXIT: *
* *
* Returns the handle returned by EMMallocpages(). *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
int test_EMMallocpages(int pages)
{
int handle;
/* call EMMallocpages() and check the return */
handle = EMMallocpages(pages);
weirdcodechk("EMMallocpages()", 0, NULL, 0, 0);
return handle;
} /* end of test_EMMallocpages() */
/***************************************************************************
* FUNCTION: TEST_EMMFREE *
* *
* DESCRIPTION: *
* *
* This function calls EMSLIB function EMMfree() and checks the *
* return codes. *
* *
* ENTRY: *
* *
* handle - EMS handle to be freed *
* *
* EXIT: *
* *
* Void. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void test_EMMfree(int handle)
{
int status;
/* call EMMfree() and check the return */
status = EMMfree(handle);
TRIPLECHECK("EMMfree()", status, 0, NULL, 0, 0);
return;
} /* end of test_EMMfree() */
/***************************************************************************
* FUNCTION: TEST_EMMMAPPAGE *
* *
* DESCRIPTION: *
* *
* This function calls EMSLIB function EMMmappage() and checks the *
* return codes. *
* *
* ENTRY: *
* *
* frameno - frame number to map page into *
* handle - handle of page to be mapped *
* logpage - page number to map *
* *
* EXIT: *
* *
* Void. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void test_EMMmappage(int frameno, int handle, int logpage)
{
int status;
/*
** do sanity check on frame number, just in case -- we shouldn't be
** trying to map into frames other than standard 0 through 3.
*/
if ((frameno < 0) || (frameno > 3))
{
printf("Sanity check failed, trying to map to frame %d, aborting.\n",
frameno);
EMMfree(handle);
exit(3);
}
/* call EMMmappage() and check return */
status = EMMmappage(frameno, handle, logpage);
TRIPLECHECK("EMMmappage()", status, 0, NULL, handle, 0);
return;
} /* end of test_EMMmappage() */
/*
** The following group of functions are used to speed up return checking
** and keep code size down, since the return check only has to be coded
** in one place. They are used in various macros to further compact and
** clarify the code.
*/
/***************************************************************************
* FUNCTION: WEIRDRETCHK *
* *
* DESCRIPTION: *
* *
* This function checks to see if the status value passed to it is *
* either 0 or EMMOOPS, and assumes something has gone wrong if it *
* is not. If something has gone wrong, does some clean up before *
* exiting. *
* *
* ENTRY: *
* *
* function - name of function which may have goofed *
* status - status value to check *
* tofree1 - conventional memory block to be freed on exit. Not *
* freed if NULL. *
* tofree2 - EMS handle to be freed on exit. Not freed if 0. *
* tofree2 - another EMS handle to be freed on exit. Not freed if 0. *
* *
* EXIT: *
* *
* Void, or may not return. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void weirdretchk(char *function, int status, void *tofree1, int tofree2,
int tofree3)
{
if ((status != EMMOOPS) && (status != 0))
{
printf("%s returned weird value %d, code 0x%X.\n", function, status,
(unsigned int) _EMMerror);
if (tofree1 != (void *) NULL)
{
free(tofree1);
}
if (tofree2 != 0)
{
EMMfree(tofree2);
}
if (tofree3 != 0)
{
EMMfree(tofree3);
}
exit(3);
}
return;
} /* end of weirdretchk() */
/***************************************************************************
* FUNCTION: WEIRDCODECHK *
* *
* DESCRIPTION: *
* *
* This function checks to see if the EMSLIB error code value matches *
* the expected value, and assumes something has gone wrong if it *
* does not. If something has gone wrong, does some clean up before *
* exiting. *
* *
* ENTRY: *
* *
* function - name of function which may have goofed *
* expected - expected value of _EMMerror *
* tofree1 - conventional memory block to be freed on exit. Not *
* freed if NULL. *
* tofree2 - EMS handle to be freed on exit. Not freed if 0. *
* tofree2 - another EMS handle to be freed on exit. Not freed if 0. *
* *
* EXIT: *
* *
* Void, or may not return. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void weirdcodechk(char *function, int expected, void *tofree1, int tofree2,
int tofree3)
{
if ((int) _EMMerror != expected)
{
printf("%s returned unexpected code 0x%X.\n", function,
(unsigned int) _EMMerror);
if (tofree1 != (void *) NULL)
{
free(tofree1);
}
if (tofree2 != 0)
{
EMMfree(tofree2);
}
if (tofree3 != 0)
{
EMMfree(tofree3);
}
exit(3);
}
return;
} /* end of weirdcodechk() */
/***************************************************************************
* FUNCTION: FAILCHECK *
* *
* DESCRIPTION: *
* *
* This function checks to see if the status value passed to it is *
* EMMOOPS and exits if it is. failcheck() is used when a function *
* is expected to succeed. Does some clean up before exiting. *
* *
* ENTRY: *
* *
* function - name of function which may have goofed *
* status - status value to be checked *
* tofree1 - conventional memory block to be freed on exit. Not *
* freed if NULL. *
* tofree2 - EMS handle to be freed on exit. Not freed if 0. *
* tofree2 - another EMS handle to be freed on exit. Not freed if 0. *
* *
* EXIT: *
* *
* Void, or may not return. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void failcheck(char *function, int status, void *tofree1, int tofree2,
int tofree3)
{
if (status == EMMOOPS)
{
printf("%s failed, code 0x%X.\n", function, (unsigned int) _EMMerror);
if (tofree1 != (void *) NULL)
{
free(tofree1);
}
if (tofree2 != 0)
{
EMMfree(tofree2);
}
if (tofree3 != 0)
{
EMMfree(tofree3);
}
exit(3);
}
return;
} /* end of failcheck() */
/***************************************************************************
* FUNCTION: NOFAILCHECK *
* *
* DESCRIPTION: *
* *
* This function checks to see if the status value passed to it is *
* 0 and exits if it is. nofailcheck() is used when a function is *
* expected to fail. Does some clean up before exiting. *
* *
* ENTRY: *
* *
* function - name of function which may have goofed *
* status - status value to be checked *
* tofree1 - conventional memory block to be freed on exit. Not *
* freed if NULL. *
* tofree2 - EMS handle to be freed on exit. Not freed if 0. *
* tofree2 - another EMS handle to be freed on exit. Not freed if 0. *
* *
* EXIT: *
* *
* Void, or may not return. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void nofailcheck(char *function, int status, void *tofree1, int tofree2,
int tofree3)
{
if (status == 0)
{
printf("%s did not fail.\n", function);
if (tofree1 != (void *) NULL)
{
free(tofree1);
}
if (tofree2 != 0)
{
EMMfree(tofree2);
}
if (tofree3 != 0)
{
EMMfree(tofree3);
}
exit(3);
}
return;
} /* end of nofailcheck() */
/*
** The following functions are utility functions used to fill and check
** blocks of memory and perform other basic services. Many are coded in
** in-line assembly language to improve speed. The in-line assembly is
** compatible with both Turbo/Borland C[++] and MSC 6.00A. If your compiler
** does not support in-line assembly, or the compiler requires an external
** assembler which you do not have, the functions contain alternate C code.
** In fact, in order to get the in-line assembly, you must define the symbol
** INLINE_ASM.
*/
/***************************************************************************
* FUNCTION: FARMEMCHECK *
* *
* DESCRIPTION: *
* *
* This function scans a block of memory looking for bytes which do *
* not match checkchar. *
* *
* ENTRY: *
* *
* buffer - pointer to block of memory to scan *
* len - length of block *
* checkchar - value which should be matched *
* *
* EXIT: *
* *
* Returns 0 if all bytes match, nonzero if mismatch found. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
int farmemcheck(unsigned char far *buffer, unsigned int len,
unsigned char checkchar)
{
int retval = 0;
unsigned char huge *temp;
/* normalize far pointer and turn into huge pointer */
temp = normptr(buffer);
#ifdef INLINE_ASM
ASM push bx /* preserve registers */
ASM push cx
ASM push si
ASM push ds
ASM lds si, [temp] /* load pointer into DS:SI */
ASM mov cx, [len] /* load length into CX */
ASM mov bl, [checkchar] /* load match value into BX */
looptop:
ASM lodsb /* load next byte into AL */
ASM cmp al, bl /* test against BL */
ASM jne nomatch /* if not equal, exit loop */
ASM loop looptop /* otherwise loop */
ASM jmp match
nomatch:
ASM mov retval, 1 /* return nonzero on mismatch */
match:
ASM pop ds /* restore register values */
ASM pop si
ASM pop cx
ASM pop bx
#else
for (; len; len--, temp++) /* do the same thing in C */
{
if (*temp != checkchar)
{
retval = 1;
break;
}
}
#endif
return retval;
} /* end of farmemcheck() */
/***************************************************************************
* FUNCTION: FARINCWORDFILL *
* *
* DESCRIPTION: *
* *
* Fill a region of memory with incrementing word (16 bit) values. *
* Always starts at 0 value. *
* *
* ENTRY: *
* *
* buffer - pointer to block of memory *
* len - length of block, must be even *
* *
* EXIT: *
* *
* Void. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void farincwordfill(unsigned char far *buffer, unsigned int len)
{
unsigned char huge *temp;
#ifndef INLINE_ASM
int loop;
int huge *filler;
#endif
/* turn length in bytes into length in words, convert pointer */
len /= 2;
temp = normptr(buffer);
#ifdef INLINE_ASM
ASM push ax /* preserve registers */
ASM push cx
ASM push di
ASM push es
ASM les di, [temp] /* load pointer into ES:DI */
ASM mov cx, [len] /* load length into CX */
ASM xor ax, ax /* zero AX */
loop2top:
ASM stosw /* store AX in memory, DI += 2 */
ASM inc ax /* increment AX */
ASM loop loop2top /* loop */
ASM pop es /* restore register values */
ASM pop di
ASM pop cx
ASM pop ax
#else
/* do the same thing in C */
for (loop = 0, filler = (int huge *) temp; loop < len; loop++)
{
*filler = loop;
}
#endif
return;
} /* end of farincwordfill() */
/***************************************************************************
* FUNCTION: FARINCWORDCHECK *
* *
* DESCRIPTION: *
* *
* Scans a block of memory to make sure contents are incrementing *
* word values. *
* *
* ENTRY: *
* *
* buffer - pointer to block of memory *
* len - length of block of memory, must be even *
* *
* EXIT: *
* *
* Returns 0 if contents are OK, nonzero if mismatch found. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
int farincwordcheck(unsigned char far *buffer, unsigned int len)
{
int retval = 0;
unsigned char huge *temp;
#ifndef INLINE_ASM
int loop;
int huge *filler;
#endif
/* convert length in bytes to length in words, convert pointer */
len /= 2;
temp = normptr(buffer);
#ifdef INLINE_ASM
ASM push ax /* preserve register values */
ASM push bx
ASM push cx
ASM push si
ASM push ds
ASM lds si, [temp] /* load pointer into DS:SI */
ASM mov cx, [len] /* load length into CX */
ASM xor bx, bx /* zero BX */
ASM dec bx /* decrement BX, ready for loop */
loop3top:
ASM inc bx /* increment BX to next value */
ASM lodsw /* load next word into AX */
ASM cmp ax, bx /* compare word in AX and BX */
ASM loope loop3top /* loop while words are equal */
ASM je done /* exited loop -- if last cmp */
/* was equal, jump to end, else */
ASM mov retval, 1 /* mismatch, set nonzero retval */
done:
ASM pop ds /* restore register values */
ASM pop si
ASM pop cx
ASM pop bx
ASM pop ax
#else
/* do the same thing in C */
for (loop = 0, filler = (int huge *) temp; loop < len; loop++)
{
if (*filler != loop)
{
retval = 1;
break;
}
}
#endif
return retval;
} /* end of farincwordcheck() */
/***************************************************************************
* FUNCTION: FARINCLONGFILL *
* *
* DESCRIPTION: *
* *
* Fills a region of memory with incrementing longword (32 bit) *
* values. This function was not coded in assembly because it has *
* to handle regions > 64K, which is a pain in the neck. *
* *
* ENTRY: *
* *
* buffer - pointer to block of memory *
* len - length of block of memory, must be multiple of 4 *
* start - value to start incrementing from *
* *
* EXIT: *
* *
* Void. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void farinclongfill(unsigned char far *buffer, unsigned long len,
unsigned long start)
{
unsigned long loop;
unsigned long huge *filler;
/* convert length in bytes to length in longwords */
len /= 4;
/* fill */
for (loop = 0L, filler = (unsigned long huge *) normptr(buffer);
loop < len; loop++, filler++)
{
*filler = start++;
}
return;
} /* end of farinclongfill() */
/***************************************************************************
* FUNCTION: FARINCLONGCHECK *
* *
* DESCRIPTION: *
* *
* Scans a region of memory checking that it contains incrementing *
* longword values. This function was not coded in assembly because *
* it has to handle regions > 64K, which is a pain in the neck. *
* *
* ENTRY: *
* *
* buffer - pointer to block of memory *
* len - length of block of memory *
* start - value to start incrementing from *
* *
* EXIT: *
* *
* Returns 0 if values OK, nonzero if mismatch found. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
int farinclongcheck(unsigned char far *buffer, unsigned long len,
unsigned long start)
{
unsigned long loop;
unsigned long huge *filler;
int retval = 0;
/* convert length in bytes to length in longwords */
len /= 4;
/* scan */
for (loop = 0L, filler = (unsigned long huge *) normptr(buffer);
loop < len; loop++, filler++)
{
if (*filler != start++)
{
retval = 1;
break;
}
}
return retval;
} /* end of farinclongcheck() */
/***************************************************************************
* FUNCTION: GET_TICK *
* *
* DESCRIPTION: *
* *
* Retrieves the current timer count via BIOS call. For use when *
* timing copies. The timer ticks 18.2 times per second. The value *
* returned by this function has a jitter of -0,+(1/18.2) seconds. *
* *
* ENTRY: *
* *
* Void. *
* *
* EXIT: *
* *
* Returns the timer count. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
unsigned long get_tick(void)
{
unsigned long retval;
#ifdef INLINE_ASM
ASM push cx /* push register values */
ASM push dx
ASM xor ah, ah /* AH = 00h, get count call */
ASM int 1Ah /* make call */
ASM mov WORD PTR [retval + 2], cx /* save returned value */
ASM mov WORD PTR [retval], dx
ASM pop dx
ASM pop cx
#else
union REGS r;
/* do the same thing in C */
r.h.ah = 0x0;
int86(0x1A, &r, &r);
retval = r.x.cx;
retval <<= 16;
retval |= r.x.dx;
#endif
return retval;
} /* end of get_tick() */
/*
** The following group of functions is the same in spirit as the preceding
** group, but already exist in the libraries of some compilers. These
** functions are only used if the symbol NO_FFUNC is defined, which should
** only be done when the compiler's library does not already contain these
** functions.
*/
#ifdef NO_FFUNC
/***************************************************************************
* FUNCTION: FMEMCMP *
* *
* DESCRIPTION: *
* *
* A replacement _fmemcmp() function for compilers which do not have *
* it in their libraries. Compares two regions of memory. *
* *
* ENTRY: *
* *
* buf1 - pointer to first region *
* buf2 - pointer to second region *
* n - length of regions *
* *
* EXIT: *
* *
* Returns 0 on match, negative if mismatch byte in buf1 is less than *
* corresponding byte in buf2, positive if vice versa. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
int Fmemcmp(void far *buf1, void far *buf2, unsigned int n)
{
unsigned char huge *temp1, huge *temp2;
int retval = 0;
#ifndef INLINE_ASM
int loop;
#endif
/* normalize pointers */
temp1 = normptr((unsigned char far *) buf1);
temp2 = normptr((unsigned char far *) buf2);
#ifdef INLINE_ASM
ASM push cx /* preserve register values */
ASM push di
ASM push si
ASM push ds
ASM push es
ASM lds si, [temp1] /* load first pointer in DS:SI */
ASM les di, [temp2] /* load second pointer in ES:DI */
ASM mov cx, [n] /* load length in CX */
ASM repz cmpsb /* compare while equal */
ASM jcxz alldone /* if CX is 0, all were equal */
ASM ja higher /* not equal, set return value */
ASM mov [retval], -1
ASM jmp alldone
higher:
ASM mov [retval], 1
alldone:
ASM pop es /* restore register values */
ASM pop ds
ASM pop si
ASM pop di
ASM pop cx
#else
/* do the same thing in C */
for (loop = 0; loop < n; loop++, temp1++, temp2++)
{
if (*temp1 == *temp2)
{
continue;
}
retval = (int) (*temp1 - *temp2);
break;
}
#endif
return retval;
} /* end of Fmemcmp() */
/***************************************************************************
* FUNCTION: FMEMSET *
* *
* DESCRIPTION: *
* *
* A replacement _fmemset() function for compilers which do not have *
* it in their libraries. Sets a region of memory to a particular *
* value. *
* *
* ENTRY: *
* *
* s - pointer to region of memory *
* c - byte value to set memory to *
* n - length of region *
* *
* EXIT: *
* *
* Returns s. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
void Fmemset(void far *s, int c, unsigned int n)
{
unsigned char huge *temp;
/* normalize pointer */
temp = normptr((unsigned char far *) s);
#ifdef INLINE_ASM
/* if length is odd, use slower way */
if ((n % 2) == 1)
{
ASM push ax /* preserve register values */
ASM push cx
ASM push di
ASM push es
ASM les di, [temp] /* load pointer into ES:DI */
ASM mov al, BYTE PTR [c] /* load value into AL */
ASM mov cx, [n] /* load length into CX */
ASM rep stosb /* store value in memory */
ASM pop es /* restore register values */
ASM pop di
ASM pop cx
ASM pop ax
}
else
{
/* otherwise use faster way, storing entire words at once */
/* convert length in bytes to length in words */
n /= 2;
ASM push ax /* preserve register values */
ASM push cx
ASM push di
ASM push es
ASM les di, [temp] /* load pointer into ES:DI */
ASM mov al, BYTE PTR [c] /* load value into AL */
ASM mov ah, al /* load value into AH too */
ASM mov cx, [n] /* load length into CX */
ASM rep stosw /* store value in memory by words */
ASM pop es /* restore register values */
ASM pop di
ASM pop cx
ASM pop ax
}
#else
/* do the same thing in C */
for (; n; n--, temp++)
{
*temp = c;
}
#endif
return;
} /* end of Fmemset() */
#endif
/***************************************************************************
* FUNCTION: NORMPTR (STATIC) *
* *
* DESCRIPTION: *
* *
* Normalizes a far pointer -- reduces the offset to the smallest *
* possible value (somewhere between 0 and 0xF) by adding to the *
* segment. *
* *
* ENTRY: *
* *
* norm - pointer to be normalized *
* *
* EXIT: *
* *
* Returns normalized pointer. *
* *
* CONSTRAINTS/SIDE EFFECTS: *
* *
***************************************************************************/
static unsigned char huge *normptr(unsigned char far *norm)
{
unsigned char huge *retval = (unsigned char huge *) norm;
#ifdef INLINE_ASM
ASM push cx /* preserve register values */
ASM push di
ASM push si
ASM mov si, WORD PTR [retval] /* load offset into SI */
ASM mov di, si /* load offset into DI too */
ASM mov cl, 4 /* load 4 into CL */
ASM shr di, cl /* shift DI right by 4, which */
/* converts it to a segment */
ASM add WORD PTR [retval + 2], di /* add to segment in pointer */
ASM and si, 0Fh /* zero all but lowest nibble */
/* of offset */
ASM mov WORD PTR [retval], si /* put offset back in pointer */
ASM pop si /* restore register values */
ASM pop di
ASM pop cx
#else
unsigned int segment, offset;
/* do the same thing in C -- extract segment and offset from pointer */
segment = FP_SEG(retval);
offset = FP_OFF(retval);
/* add high three nibbles of offset to segment */
segment += (offset >> 4);
/* preseve only lowest nibble of offset */
offset &= 0xF;
/* reconstruct pointer from modified segment and offset */
retval = MK_FP(segment, offset);
#endif
return retval;
} /* end of static normptr() */